package com.sense.cloud.coreservice.sdk.auth.utils.http;

import com.sense.cloud.coreservice.sdk.auth.utils.MD5Utils;
import com.sense.cloud.coreservice.sdk.auth.utils.SdkPropUtil;
import com.sense.cloud.coreservice.sdk.auth.utils.StringUtils;
import com.sense.cloud.coreservice.sdk.auth.utils.http.assist.AuthConstants;
import com.sense.cloud.coreservice.sdk.auth.utils.http.assist.HttpClientConnectionManagerWrapper;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

/**
 * @date 2017.01.01
 * @author wx
 * @info 鉴权调用的工具类，安装鉴权协议公式做的参考demo，提供get、post请求的方法供Java应用调用；
 */
public class AuthSdkHttpRequest {
  private static final Logger log = LoggerFactory.getLogger(AuthSdkHttpRequest.class);

  private static String ssaccesskey = SdkPropUtil.getAccessKey(); // accessKey
  private static String sssecret = SdkPropUtil.getSecret(); // secret

  // 属性字段
  // 是否使用HttpClient连接池，默认不使用
  private boolean isUseHttpClientPool = false;
  // 请求的URL地址
  private String url;

  // HttpClient连接超时时间1分钟默认
  private int connectTimeOut = 60000;
  private int socketTimeOut = 60000;
  // 设置请求头配置信息
  protected Map<String, String> headers = new HashMap<>();

  /**
   * @info 构造函数
   * @param url.
   */
  public AuthSdkHttpRequest(String url) {
    this.url = url;
  }

  /**
   * @info 设置连接超时时间
   * @param connectTimeOut.
   * @return this.
   */
  public AuthSdkHttpRequest setConnectTimeOut(int connectTimeOut) {
    this.connectTimeOut = connectTimeOut;
    return this;
  }

  /**
   * @info 设置socket超时时间
   * @param connectTimeOut.
   * @return this.
   */
  public AuthSdkHttpRequest setSocketTimeOut(int socketTimeOut) {
    this.socketTimeOut = socketTimeOut;
    return this;
  }

  /**
   * @info 配置请求头文件
   * @param kv.
   * @return this.
   */
  public AuthSdkHttpRequest addHeader(String key, String value) {
    headers.put(key, value);
    return this;
  }

  /**
   * @info 配置请求头JSON请求
   * @param kv.
   * @return this.
   */
  public AuthSdkHttpRequest setHeaderContentTypeJson() {
    headers.put("Content-Type", "application/json");
    return this;
  }

  /**
   * @info 配置请求头XML请求
   * @param kv.
   * @return this.
   */
  public AuthSdkHttpRequest setHeaderContentTypeXml() {
    headers.put("Content-Type", "application/xml");
    return this;
  }

  /**
   * @info 配置是否使用HTTPclient连接池
   * @param kv.
   * @return this.
   */
  public AuthSdkHttpRequest isUseHttpClientPool(boolean b11) {
    this.isUseHttpClientPool = b11;
    return this;
  }

  /**
   * 
   * @param GET方法传递的键值对信息集合
   * @return String.
   * @throws Exception exec.
   */
  public String get(Map<String, String> params) throws Exception {
    Map<String, String> map = StringUtils.queryStr2Map(url);
    if ( map != null && map.size() > 0 ) {
      params.putAll(map);
    }

    String paramSb = paramsMap2SortAndEncodeString(params);

    String signStr = StringUtils.getAction(url) + paramSb 
            + AuthConstants.SECRET + "=" + sssecret;

    log.debug("GET SIGN URL ------------>01 \n\n\t" + signStr + " \n\n ");

    String sssign = MD5Utils.md5(signStr.getBytes(AuthConstants.CHAR_CODE));
    paramSb += AuthConstants.SIGN + "=" + sssign;

    String reqStr = StringUtils.getHttpIpPort(url) + StringUtils.getAction(url) + paramSb;
    
    log.debug("GET REQ  URL------------>02 \n\n\t" + reqStr + " \n\n ");

    HttpGet httpReq = new HttpGet(reqStr);

    // 进行请求
    return sendRequest(httpReq);
  }

  /**
   * 
   * @param entity，POST请求的数据体
   * @return String.
   * @throws Exception exec.
   */
  public String post(HttpEntity entity) throws Exception {

    
    Map<String, String> params = StringUtils.queryStr2Map(url);
    String  paramSb = paramsMap2SortAndEncodeString(params);

    String signStr = StringUtils.getAction(url) + paramSb + AuthConstants.SECRET 
         + "=" + sssecret;

    log.debug("POST SIGN URL ------------>01 \n\n\t" + signStr + " \n\n ");

    // body数据签名
    byte[] b1 = signStr.getBytes(AuthConstants.CHAR_CODE);
    byte[] b2 = null;
    byte[] data = null;

    if (entity == null) {
      data = new byte[b1.length];
      System.arraycopy(b1, 0, data, 0, b1.length);
    } else {
      b2 = EntityUtils.toByteArray(entity);
      data = new byte[b1.length + b2.length];
      System.arraycopy(b1, 0, data, 0, b1.length);
      System.arraycopy(b2, 0, data, b1.length, b2.length);
    }

    String sssign = MD5Utils.md5(data);
    paramSb += AuthConstants.SIGN + "=" + sssign;

    String reqStr = StringUtils.getHttpIpPort(url) 
           + StringUtils.getAction(url) + paramSb;
    
    log.debug("POST REQ  URL------------>02 \n\n\t" + reqStr + " \n\n ");

    HttpPost httpReq = new HttpPost(reqStr);
    httpReq.setEntity(entity);

    // 进行请求
    return sendRequest(httpReq);
  }

  /**
   * 
   * @param HttpRequestBase.
   * @return String.
   * @throws Exception exec.
   */
  private String sendRequest(HttpRequestBase httpReq) throws Exception {

    // 配置连接超时等属性
    RequestConfig config = RequestConfig.custom()
        .setSocketTimeout(socketTimeOut)
        .setConnectTimeout(connectTimeOut)
        .build();
    httpReq.setConfig(config);

    // 设置http header属性
    if (headers != null && !headers.isEmpty()) {
      Iterator<Entry<String, String>> itr = headers.entrySet().iterator();
      while (itr.hasNext()) {
        Entry<String, String> entry = itr.next();
        httpReq.addHeader(entry.getKey(), entry.getValue());
      }
    }

    CloseableHttpClient httpClient = null;
    CloseableHttpResponse response = null;

    // 是否使用连接池？
    if (isUseHttpClientPool == true) {
      httpClient = HttpClientConnectionManagerWrapper.getHttpClient();
    } else {
      httpClient = HttpClients.createDefault();
    }
    // 处理请求
    try {
      response = httpClient.execute(httpReq);
      if (response.getStatusLine().getStatusCode() == 200) {
        HttpEntity entity = response.getEntity();
        String content = EntityUtils.toString(entity, AuthConstants.CHAR_CODE);
        return content;

        // 自定义的错误码，会返回服务验证不合理信息提示
      } else if (response.getStatusLine().getStatusCode() == 401) {
        HttpEntity entity = response.getEntity();
        String content = EntityUtils.toString(entity, AuthConstants.CHAR_CODE);
        return content;

      } else {
        // 返回非200状态码的时候也应消费掉消息，以确保内部流被关闭
        HttpEntity entity = response.getEntity();
        EntityUtils.consume(entity);

        throw new Exception("http request failed, status code:" 
                + response.getStatusLine().getStatusCode());
      }
    } catch (Exception e11) {
      log.error(e11.getMessage(), e11);
      throw e11;
    } finally {
      // 关闭连接
      if (isUseHttpClientPool == false && httpClient != null) {
        httpClient.close();
      }
      // 释放请求
      if (httpReq != null) {
        httpReq.releaseConnection();
      }
      try {
        if (response != null) {
          response.close();
        }
      } catch (Exception e2) {
        log.error(e2.getMessage(), e2);
      }
    }
  }

  private String paramsMap2SortAndEncodeString(Map<String, String> params) {
    StringBuilder paramSb = new StringBuilder("?");
    try {
      // 设置url和参数,对参数进行URLEncode
      if (params != null && !params.isEmpty()) {
        // 排序，按照公式要求需要进行字典排序
        params = StringUtils.sortMap(params);

        Iterator<Entry<String, String>> itr = params.entrySet().iterator();
        while (itr.hasNext()) {
          Entry<String, String> entry = itr.next();
          paramSb.append(entry.getKey()).append("=");
          paramSb.append(URLEncoder.encode(entry.getValue(), AuthConstants.CHAR_CODE)).append("&");

        }
      }
      // ?aa=xxx&bb=xxx&

      // 特殊信息,应用鉴权的参数
      String ssnonce = StringUtils.getUniqeLowerCaseStringWithuuid();
      paramSb.append(AuthConstants.ACCESSKEY).append("=").append(ssaccesskey).append("&");
      paramSb.append(AuthConstants.NONCE).append("=").append(ssnonce).append("&");

      return paramSb.toString();
    } catch (UnsupportedEncodingException e11) {
      e11.printStackTrace();
    }
    return paramSb.toString();
  }

  

  

}
